#
# Copyright 2009, Jeffrey Palm.
#

#
# A very basic server that talks TCP and has 1 handler of every
# request.
#

require 'socket'
require 'util'

#
# A simple server that can have one handler handling all the requests.
#
class Server

  # The sole recipient of every message
  attr_accessor :handler

  # Use this to control when we're done listening on the socket.  Set
  # it to 'true' to mean that we should break out of the listen-loop.
  attr_accessor :done

  def initialize(handler=nil)
    @handler = handler
    @done    = false
  end

  # A handler will be given certain types of requests.  THe one
  # instance of this in the Server will take requests and then decide
  # when the Server should stop listening on the socket.
  class Handler

    # A descriptive name
    attr_reader :name

    def initialize(name)
      @name  = name
    end

    # The abstract method that all subclasses must implement.  This is
    # called with the request that satisfied the regular expression.
    #
    # The return value of this method should be whether we are done, i.e.:
    #  - true  : stop and close the socket
    #  - false : continue on listening on the socket
    #
    def handle(request)
      throw '\'handle\' must be implemented by subclasses'
    end

    # Returns the name
    def to_s
      @name
    end

  end
  
  # The main entry point to start a local HTTP server
  # - addr: ip address on which we listen (probably localhost)
  # - port: port on which we listen
  def start(addr,port)

    note 'Starting server'
    note 'Listening on host : ' + addr.to_s
    note 'Listening on port : ' + port.to_s
    note 'Local ip address  : ' + private_ip_address

    # Create the TCP Server and set 'done' to false, the handler will
    # set it to true when she takes care of business
    server = TCPServer.new addr,port
    @done  = false
    while not @done
      
      note 'Waiting for a connection'
      session = server.accept
      request = session.gets

      # Spawn a new thread to let the handler do her thang and set
      # 'done' accordingly.  Once 'done' is true we're (uh) done.
      Thread.start(session,request) do |session,request| 
        @done = @handler.handle request
      end
    end
  end
end
